﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Windows;
using System.Windows.Shapes;

namespace Gencode.VECore.VectorShape
{
	public class VECRectangle : VECShape
	{
        /// <summary>
        /// Rectangle that describes size and position
        /// </summary>
		Rect _rectangle;
        /// <summary>
        /// Serializer object description
        /// </summary>
        private const string serRectangleString = "Rect";

        public VECRectangle()
            : this(0, 0, 1, 1)
        {
        }

		public VECRectangle(Point point, Size size)
			: this(point.X, point.Y, size.Width, size.Height)
		{
		}


		public VECRectangle(double x, double y, double width, double height)
		{
			_definingGeometry = new RectangleGeometry();
			_rectangle = new Rect(x, y, width, height);
			_definingGeometry.Rect = _rectangle;

			this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(MouseLeftUp);

			this.Focusable = true;
		}

        /// <summary>
        /// Clone this instance
        /// </summary>
        public override VECShape Clone()
        {
            VECRectangle drawRect = new VECRectangle();
            drawRect.Rectangle = this.Rectangle;

            CopyShapeProperies(drawRect);
            return drawRect;
        }

		RectangleGeometry _definingGeometry;
		protected override Geometry DefiningGeometry
		{
			get
			{
				if (_definingGeometry == null)
					_definingGeometry = new RectangleGeometry();

				return _definingGeometry;
			}
		}

		public new double Width
		{
			get
			{
				return _definingGeometry.Rect.Width;
			}
			set
			{
				_rectangle.Width = value;
				_definingGeometry.Rect = _rectangle;
			}
		}

		public new double Height
		{
			get
			{
				return _definingGeometry.Rect.Height;
			}
			set
			{
				_rectangle.Height = value;
				_definingGeometry.Rect = _rectangle;
			}
		}

		public double X
		{
			get
			{
				return _definingGeometry.Rect.X;
			}
			set
			{
				_rectangle.X = value;
				_definingGeometry.Rect = _rectangle;
			}
		}

		public double Y
		{
			get
			{
				return _definingGeometry.Rect.Y;
			}
			set
			{
				_rectangle.Y = value;
				_definingGeometry.Rect = _rectangle;
			}
		}

		public double Right
		{
			get
			{
				return _rectangle.Right;
			}
		}

		public double Left
		{
			get
			{
				return _rectangle.Left;
			}
		}

        public Rect Rectangle
        {
            get
            {
                return _rectangle;
            }
            set
            {
                _rectangle = value;
                _definingGeometry.Rect = _rectangle;
            }
        }

		protected override void OnRender(DrawingContext drawingContext)
		{
			base.OnRender(drawingContext);

			if (Selected)
			{
				Pen p = new Pen(Brushes.Blue,1);
				drawingContext.DrawEllipse(Brushes.LightBlue, p, new Point(X, Y), 2.5, 2.5);
				drawingContext.DrawEllipse(Brushes.LightBlue, p, new Point(X + Width, Y), 2.5, 2.5);
				drawingContext.DrawEllipse(Brushes.LightBlue, p, new Point(X, Y + Height), 2.5, 2.5);
				drawingContext.DrawEllipse(Brushes.LightBlue, p, new Point(X + Width, Y + Height), 2.5, 2.5);
			}
		}

		private void MouseLeftUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			if (CanvasDocument.SelectedToolType == Gencode.VECore.ToolType.SelectionTool)
			{
				if (!Selected)
				{
                    //CanvasManager.SelectedObject = this;
					Selected = true;
				}
			}
		}



		/// <summary>
		/// Get number of handles
		/// </summary>
		public override int HandleCount
		{
			get
			{
				return 4;
			}
		}


		/// <summary>
		/// Get handle point by 1-based number
		/// </summary>
		/// <param name="handleNumber"></param>
		/// <returns></returns>
		public override Point GetHandle(int handleNumber)
		{
			double x, y;
			x = _rectangle.X;
			y = _rectangle.Y;

			switch (handleNumber)
			{
				case 1:
					x = _rectangle.X;
					y = _rectangle.Y;
					break;
				case 2:
					x = _rectangle.Right;
					y = _rectangle.Y;
					break;
				case 3:
					x = _rectangle.Right;
					y = _rectangle.Bottom;
					break;
				case 4:
					x = _rectangle.X;
					y = _rectangle.Bottom;
					break;
			}

			return new Point(x, y);
		}

		/// <summary>
		/// Hit test.
		/// Return value: -1 - no hit
		///                0 - hit anywhere
		///                > 1 - handle number
		/// </summary>
		/// <param name="point"></param>
		/// <returns></returns>
		public override int HitTest(Point point)
		{
			if (Selected)
			{
				for (int i = 1; i <= HandleCount; i++)
				{
					if (GetHandleRectangle(i).Contains(point))
						return i;
				}
			}

			if (PointInObject(point))
				return 0;

			return -1;
		}

		protected override bool PointInObject(Point point)
		{
			return _rectangle.Contains(point);
		}

		/// <summary>
		/// Move handle to new point (resizing)
		/// </summary>
		/// <param name="point"></param>
		/// <param name="handleNumber"></param>
		public override void MoveHandle(Point point, int handleNumber)
		{
			double left = _rectangle.Left;
			double top = _rectangle.Top;
			double right = _rectangle.Right;
			double bottom = _rectangle.Bottom;

			switch (handleNumber)
			{
				case 1:
					left = point.X;
					top = point.Y;
					break;
				case 2:
					right = point.X;
					top = point.Y;
					break;
				case 3:
					right = point.X;
					bottom = point.Y;
					break;
				case 4:
					left = point.X;
					bottom = point.Y;
					break;
			}

			SetRectangle(left, top, right - left, bottom - top);

            CallChangedHandler();
		}

		protected void SetRectangle(double x, double y, double width, double height)
		{
			try
			{
				_rectangle.X = x;
				_rectangle.Y = y;
				_rectangle.Width = width;
				_rectangle.Height = height;

				_definingGeometry.Rect = _rectangle;
				this.InvalidateVisual();
			}
			catch { }
		}

        public override void Move(double deltaX, double deltaY)
        {
            _rectangle.X += deltaX;
            _rectangle.Y += deltaY;
            _definingGeometry.Rect = _rectangle;
            this.InvalidateVisual();

            CallMovedHandler();
        }

		/// <summary>
		/// Get cursor for the handle
		/// </summary>
		/// <param name="handleNumber"></param>
		/// <returns></returns>
		public override System.Windows.Input.Cursor GetHandleCursor(int handleNumber)
		{
			switch (handleNumber)
			{
				case 1:
					return System.Windows.Input.Cursors.SizeNWSE;
				case 2:
					return System.Windows.Input.Cursors.SizeNESW;
				case 3:
					return System.Windows.Input.Cursors.SizeNWSE;
				case 4:
					return System.Windows.Input.Cursors.SizeNESW;
				default:
					return System.Windows.Input.Cursors.Arrow;
			}
		}

        public override bool IntersectsWith(Rect rectangle)
        {
            return _rectangle.IntersectsWith(rectangle);
        }

        public override void SaveToStream(System.Runtime.Serialization.SerializationInfo info, int orderNumber)
        {
            info.AddValue(
                String.Format(System.Globalization.CultureInfo.InvariantCulture,
                "{0}{1}",
                serRectangleString, orderNumber),
                _rectangle);

            base.SaveToStream(info, orderNumber);
        }

        public override void LoadFromStream(System.Runtime.Serialization.SerializationInfo info, int orderNumber)
        {
            _rectangle = (Rect)info.GetValue(
                String.Format(System.Globalization.CultureInfo.InvariantCulture,
                "{0}{1}",
                serRectangleString, orderNumber),
                typeof(Rect));

            _definingGeometry.Rect = _rectangle;

            base.LoadFromStream(info, orderNumber);
        }

        #region Static Helper Functions

        public static Rect GetNormalizedRectangle(double x1, double y1, double x2, double y2)
        {
            if (x2 < x1)
            {
                int tmp = (int)x2;
                x2 = x1;
                x1 = tmp;
            }

            if (y2 < y1)
            {
                int tmp = (int)y2;
                y2 = y1;
                y1 = tmp;
            }

            return new Rect(x1, y1, x2 - x1, y2 - y1);
        }

        public static Rect GetNormalizedRectangle(Point p1, Point p2)
        {
            return GetNormalizedRectangle(p1.X, p1.Y, p2.X, p2.Y);
        }

        public static Rect GetNormalizedRectangle(Rect r)
        {
            return GetNormalizedRectangle(r.X, r.Y, r.X + r.Width, r.Y + r.Height);
        }

        #endregion
    }
}
